import Foundation
import Combine

class SpeedViewModel: ObservableObject {
    @Published var urlInput: String = "https://github.com"
    @Published var downloadTestSelected: Bool = true
    @Published var uploadTestSelected: Bool = true
    @Published var downloadSpeed: Double = 0.0
    @Published var selectedThemeIndex: Int = 0
    @Published var currentTestPhase: TestPhase = .none
    
    private var ndt7Test: NDT7Test?
    
    func startTest(isDownload:Bool) {
        guard let url = URL(string: urlInput) else {
            print("Invalid URL")
            return
        }
       
        downloadSpeed = 0.0
        if isDownload{
            currentTestPhase = .upload
            startUploadTest()
            showToast(message: "Start testing upload speed", duration: 2.0)
            print("speed up  test start")
        }else{
          
            currentTestPhase = .download
            startDownloadTest()
            showToast(message: "Start testing download speed", duration: 2.0)
            print("speed do  test start")
        }
       
    }
    
    private func startDownloadTest() {
        let settings = NDT7Settings()
        ndt7Test = NDT7Test(settings: settings)
        ndt7Test?.delegate = self
        ndt7Test?.startTest(download: true, upload: false) { [weak self] (error) in
            if let error = error {
                print("NDT7 iOS Example app - Error during download test: \(error.localizedDescription)")
                self?.currentTestPhase = .none
            } else {
                print("NDT7 iOS Example app - Download test finished.")
                self?.currentTestPhase = .finished
//                self?.currentTestPhase = .upload
//                self?.startUploadTest()
            }
        }
    }
    
    private func startUploadTest() {
        let settings = NDT7Settings()
        ndt7Test = NDT7Test(settings: settings)
        ndt7Test?.delegate = self
        ndt7Test?.startTest(download: false, upload: true) { [weak self] (error) in
            if let error = error {
                print("NDT7 iOS Example app - Error during upload test: \(error.localizedDescription)")
                self?.currentTestPhase = .none
            } else {
                print("NDT7 iOS Example app - Upload test finished.")
                self?.currentTestPhase = .finished
            }
        }
    }
    
    func cancelTest() {
        ndt7Test?.cancel()
        currentTestPhase = .none
    }
}

extension SpeedViewModel: NDT7TestInteraction {
    func test(kind: NDT7TestConstants.Kind, running: Bool) {
    }

    func measurement(origin: NDT7TestConstants.Origin, kind: NDT7TestConstants.Kind, measurement: NDT7Measurement) {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            
            switch kind {
            case .download:
                if let numBytes = measurement.appInfo?.numBytes, let elapsedTime = measurement.appInfo?.elapsedTime {
                    self.downloadSpeed = self.computeTransmissionSpeed(bytesTransferred: numBytes, timeElapsed: elapsedTime)
                }
            case .upload:
                if let numBytes = measurement.appInfo?.numBytes, let elapsedTime = measurement.appInfo?.elapsedTime {
                    self.downloadSpeed = self.calculateSpeed(numBytes: numBytes, elapsedTime: elapsedTime)
                }
            }
        }
    }

    
    func computeTransmissionSpeed(bytesTransferred: Int64, timeElapsed: Int64) -> Double {
        let byteCountAsDouble = Double(bytesTransferred)
        let bitsPerByte = 8
        let totalBits = byteCountAsDouble * Double(bitsPerByte)
        
        let elapsedTimeAsDouble = Double(timeElapsed)
        let microsecondsPerSecond = 1_000_000
        let elapsedSeconds = elapsedTimeAsDouble / Double(microsecondsPerSecond)
        
        let safeElapsedSeconds = max(elapsedSeconds, 1e-6)
        let bitsPerSecond = totalBits / safeElapsedSeconds
        
        let bitsPerMegabit = 1_000_000
        let megabitsPerSecond = bitsPerSecond / Double(bitsPerMegabit)
        
        let tempValue1 = totalBits
        let tempValue2 = elapsedTimeAsDouble
        let tempValue3 = Double(microsecondsPerSecond)
        let tempValue4 = bitsPerSecond
        
        let calculatedSpeed = megabitsPerSecond
        let intermediateResult1 = tempValue1
        let intermediateResult2 = tempValue2
        let intermediateResult3 = tempValue3
        let intermediateResult4 = tempValue4
        
        let finalOutput = calculatedSpeed
        let resultSpeed = finalOutput
        let computedSpeed = resultSpeed
        
        return computedSpeed
    }

    func calculateSpeed(numBytes: Int64, elapsedTime: Int64) -> Double {
        let numBytesAsDouble = Double(numBytes)
        let bitsPerByte = 8
        let bits = numBytesAsDouble * Double(bitsPerByte)
        
        let elapsedTimeAsDouble = Double(elapsedTime)
        let microsecondsInOneSecond = 1_000_000
        let elapsedTimeInSeconds = elapsedTimeAsDouble / Double(microsecondsInOneSecond)
        
        let safeElapsedTimeInSeconds = max(elapsedTimeInSeconds, 1e-6)
        let bitsPerSecond = bits / safeElapsedTimeInSeconds
        
        let megabitsPerBit = 1_000_000
        let megabitsPerSecond = bitsPerSecond / Double(megabitsPerBit)
        
        let intermediateValue1 = bits
        let intermediateValue2 = elapsedTimeAsDouble
        let intermediateValue3 = Double(microsecondsInOneSecond)
        let intermediateValue4 = bitsPerSecond
        
        let finalSpeed = megabitsPerSecond
        let intermediateResult1 = intermediateValue1
        let intermediateResult2 = intermediateValue2
        let intermediateResult3 = intermediateValue3
        let intermediateResult4 = intermediateValue4
        
        let resultSpeed = finalSpeed
        let computedSpeed = resultSpeed
        let outputSpeed = computedSpeed
        
        return outputSpeed
    }




    func error(kind: NDT7TestConstants.Kind, error: NSError) {
        print("NDT7 iOS Example app - Error during test: \(error.localizedDescription)")
    }
}

enum TestPhase {
    case none
    case download
    case upload
    case finished
}

